﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TCP多人聊天室服务端
{
    public partial class MainForm : Form
    {
        /// <summary>
        /// 服务端套接字
        /// </summary>
        Socket server;

        /// <summary>
        /// 客户端套接字
        /// </summary>
        Dictionary<string, Socket> clients = new Dictionary<string, Socket>();

        /// <summary>
        /// 服务端是否开启中
        /// </summary>
        bool flag = false;

        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            this.Init();


        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void Init()
        {
            //自动获取ipv4
            string ipv4 = "";
            NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
            foreach (NetworkInterface adater in adapters)
            {
                if (adater.Supports(NetworkInterfaceComponent.IPv4))
                {
                    UnicastIPAddressInformationCollection UniCast = adater.GetIPProperties().UnicastAddresses;
                    if (UniCast.Count > 0)
                    {
                        foreach (UnicastIPAddressInformation uni in UniCast)
                        {
                            if (uni.Address.AddressFamily == AddressFamily.InterNetwork)
                            {
                                ipv4 = uni.Address.MapToIPv4().ToString();
                                break;
                            }
                        }
                    }
                    if (ipv4.Length > 0)
                    {
                        break;
                    }
                }
            }
            //port初始设置为8888
            string port = "8888";

            this.textBox_Ip.Text = ipv4;
            this.textBox_Port.Text = port;
        }

        /// <summary>
        /// 开启服务端
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Open_Click(object sender, EventArgs e)
        {
            if (this.flag)
            {
                MessageBox.Show("服务端已开启");
                return;
            }

            try
            {
                //获取ipv4
                string ipv4 = this.textBox_Ip.Text.Trim();
                string[] numbers = ipv4.Split('.');
                byte[] iPbuffer = new byte[numbers.Length];
                for (int i = 0; i < iPbuffer.Length; i++)
                {
                    iPbuffer[i] = byte.Parse(numbers[i]);
                }
                //获取port
                string port = this.textBox_Port.Text.Trim();

                //初始化server
                server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //初始化clients
                clients = new Dictionary<string, Socket>();

                IPAddress iPaddress = new IPAddress(iPbuffer);
                EndPoint endPoint = new IPEndPoint(iPaddress, int.Parse(port));
                //绑定终端
                server.Bind(endPoint);
                //设置最大监听队列
                server.Listen(10);
                //服务端标识改为已开启
                this.flag = true;
                this.button_Close.Enabled = true;
                this.button_Open.Enabled = false;
                this.textBox_Port.Enabled = false;

                ShowMessage($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]\r\n服务端开启，ip：{ipv4}，port：{port}");

                Task task_server = Task.Run(() =>
                {
                    while (this.flag)
                    {
                        try
                        {
                            Socket client = server.Accept();
                            string key = client.RemoteEndPoint.ToString();
                            if (!clients.ContainsKey(key))
                            {
                                clients.Add(key, client);
                                ShowMessage($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]\r\n[{key}]加入聊天室");
                                byte[] stc= Encoding.Default.GetBytes($"[{key}]加入聊天室");
                                //给所有客户端都发送此消息，从而达到多人聊天的效果
                                foreach (var cli in clients.Values)
                                {
                                    cli.Send(stc);
                                }
                                ShowClient();
                            }

                            //接收消息
                            Task.Run(() =>
                            {
                                while (true)
                                {
                                    try
                                    {
                                        //申请1M缓冲内存
                                        byte[] buffer = new byte[1024 * 1024];
                                        //实际接收到的数据量
                                        int length = client.Receive(buffer);
                                        //客户端主动断开连接了
                                        if (length == 0)
                                        {
                                            ShowMessage($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]\r\n[{key}]退出聊天室");
                                            client.Shutdown(SocketShutdown.Both);
                                            if (clients.ContainsKey(key))
                                            {
                                                clients.Remove(key);
                                            }
                                            ShowClient();
                                            break;
                                        }
                                        string message = Encoding.Default.GetString(buffer, 0, length);

                                        ShowMessage($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]\r\n[{key}]--{message}");
                                        
                                        //实际接收到的字节数组
                                        byte[] real = Encoding.Default.GetBytes($"[{key}]--{message}");

                                        //给所有客户端都发送此消息，从而达到多人聊天的效果
                                        foreach (var cli in clients.Values)
                                        {
                                            cli.Send(real);
                                        }

                                        Thread.Sleep(20);
                                    }
                                    catch
                                    {
                                        break;
                                    }
                                }
                            });

                            Thread.Sleep(20);
                        }
                        catch { }
                    }
                });
            }
            catch (Exception exception)
            {
                ShowMessage(exception.Message);
                this.button_Open.Enabled = true;
                this.button_Close.Enabled = false;
                this.textBox_Port.Enabled = true;
                this.flag = false;

                if (this.server != null)
                {
                    try
                    {
                        this.server.Close();
                        this.server.Dispose();
                    }
                    catch { }
                }
            }
        }

        delegate void MyDelegate();
        /// <summary>
        /// 显示消息
        /// </summary>
        /// <param name="message"></param>
        private void ShowMessage(string message)
        {
            this.richTextBox_Message.Invoke(new MyDelegate(() =>
            {
                //文本已经超过1M，则先清空
                if (this.richTextBox_Message.TextLength >= 1024 * 1024)
                {
                    this.richTextBox_Message.Clear();
                }
                this.richTextBox_Message.AppendText(message);
                this.richTextBox_Message.AppendText("\r\n\r\n");
            }));
        }

        /// <summary>
        /// 关闭服务端
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Close_Click(object sender, EventArgs e)
        {
            if (!this.flag)
            {
                MessageBox.Show("服务端未开启");
                return;
            }

            this.button_Open.Enabled = true;
            this.button_Close.Enabled = false;
            this.textBox_Port.Enabled = true;
            this.flag = false;

            if (this.server != null)
            {
                try
                {
                    //一定把所有客户端连接关掉，再关闭服务端
                    //一定把所有客户端连接关掉，再关闭服务端
                    //一定把所有客户端连接关掉，再关闭服务端
                    foreach (var client in clients.Values)
                    {
                        client.Shutdown(SocketShutdown.Both);
                        client.Close();
                    }

                    this.server.Close();
                    this.server.Dispose();
                    ShowClient();

                    ShowMessage($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]\r\n服务端已关闭");
                }
                catch (Exception exception)
                {
                    ShowMessage(exception.Message);
                }
            }
        }

        /// <summary>
        /// 主动断开客户端连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Cut_Click(object sender, EventArgs e)
        {
            if (!this.flag)
            {
                MessageBox.Show("服务端未开启");
                return;
            }

            if (this.comboBox_Client.SelectedIndex == -1)
            {
                MessageBox.Show("未选择要断开的客户端");
                return;
            }

            string key = this.comboBox_Client.Text.Trim();

            if (!clients.ContainsKey(key))
            {
                MessageBox.Show("您选中的客户端连接不存在");
                return;
            }

            try
            {
                clients[key].Shutdown(SocketShutdown.Both);
                clients[key].Close();
                clients.Remove(key);
                ShowClient();

                ShowMessage($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]\r\n[{key}]已断开");
            }
            catch { }
        }

        /// <summary>
        /// 把客户端连接显示到下拉框中
        /// </summary>
        private void ShowClient()
        {
            this.comboBox_Client.Invoke(new MyDelegate(() =>
            {
                this.comboBox_Client.Items.Clear();
                this.comboBox_Client.Items.AddRange(clients.Keys.ToArray());
            }));
        }
    }
}
